package com.func.upload.util;

import com.func.upload.param.FileUploadParam;
import com.func.upload.param.RequestParam;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author txliu
 */
@SuppressWarnings("unused")
public class HttpUtil {

    private static final String HTTP_RPOTOCOL = "http";
    private static final String HTTPS_RPOTOCOL = "https";

    private static CloseableHttpClient createSSLClientDefault() {
        SSLContext sslContext;
        //信任所有
        try {
            sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (xcs, string) -> true).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        }  catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static String get(RequestParam requestParam) {
        CloseableHttpClient client = getClient(requestParam);
        return get(client, requestParam);
    }

    public static String post(RequestParam requestParam){
        CloseableHttpClient client = getClient(requestParam);
        return post(client, requestParam);
    }

    public static String jsonGet(RequestParam requestParam) {
        CloseableHttpClient client = getClient(requestParam);
        return jsonGet(client, requestParam);
    }

    public static String jsonPost(RequestParam requestParam) {
        CloseableHttpClient client = getClient(requestParam);
        return jsonPost(client, requestParam);
    }

    public static String uploadFile(FileUploadParam fileUploadParam){
        File file = new File(fileUploadParam.getFilePath());
        if(!file.exists()){
            throw new RuntimeException(fileUploadParam.getFilePath() + "文件不存在");
        }

        CloseableHttpClient client = getClient(fileUploadParam);

        HttpPost post = new HttpPost(fileUploadParam.getUrl());

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        fileUploadParam.getHeaders().keySet().forEach(key -> post.setHeader(key, fileUploadParam.getHeaders().get(key)));
        builder.addBinaryBody("file", file);

        post.setEntity(builder.build());

        CloseableHttpResponse response = null;
        try {
            response = client.execute(post);
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtil.close(response);
        }
        return null;
    }

    private static String get(CloseableHttpClient client, RequestParam requestParam) {
        CloseableHttpResponse resp = null;
        try {
            URIBuilder uriBuilder = new URIBuilder(requestParam.getUrl());
            for (String key : requestParam.getParams().keySet()) {
                uriBuilder.addParameter(key, requestParam.getParams().get(key));
            }

            HttpGet httpGet = new HttpGet(uriBuilder.build());

            for (String key : requestParam.getHeaders().keySet()) {
                httpGet.addHeader(key, requestParam.getHeaders().get(key));
            }
            resp = client.execute(httpGet);
            return EntityUtils.toString(resp.getEntity(), "UTF-8");
        } catch (URISyntaxException | IOException e) {
            throw new RuntimeException(e.getMessage());
        }finally {
            IOUtil.close(resp);
        }
    }

    private static String post(CloseableHttpClient client, RequestParam requestParam) {
        CloseableHttpResponse resp = null;
        try {
            HttpPost httpPost = new HttpPost(requestParam.getUrl());
            for (String key : requestParam.getHeaders().keySet()) {
                httpPost.addHeader(key, requestParam.getHeaders().get(key));
            }
            List<NameValuePair> params = new ArrayList<>();
            for (String key : requestParam.getParams().keySet()) {
                Object value = requestParam.getParams().get(key);
                params.add(new BasicNameValuePair(key, value == null ? "" : value.toString()));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(params));
            resp = client.execute(httpPost);
            return EntityUtils.toString(resp.getEntity(), "UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }finally {
            IOUtil.close(resp);
        }
    }

    private static String jsonGet(CloseableHttpClient client, RequestParam requestParam) {
        CloseableHttpResponse resp = null;
        try {
            RequestBuilder requestBuilder = RequestBuilder.get(requestParam.getUrl());
            for (String key : requestParam.getHeaders().keySet()) {
                requestBuilder.addHeader(key, requestParam.getHeaders().get(key));
            }
            requestBuilder.setEntity(new StringEntity(requestParam.getParamJson(), "UTF-8"));
            resp = client.execute(requestBuilder.build());
            return EntityUtils.toString(resp.getEntity(), "UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }finally {
            IOUtil.close(resp);
        }
    }

    private static String jsonPost(CloseableHttpClient client, RequestParam requestParam){
        CloseableHttpResponse resp = null;
        try {
            RequestBuilder requestBuilder = RequestBuilder.post(requestParam.getUrl());
            for (String key : requestParam.getHeaders().keySet()) {
                requestBuilder.addHeader(key, requestParam.getHeaders().get(key));
            }
            requestBuilder.setEntity(new StringEntity(requestParam.getParamJson(), "UTF-8"));
            resp = client.execute(requestBuilder.build());
            return EntityUtils.toString(resp.getEntity(), "UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }finally {
            IOUtil.close(resp);
        }
    }

    private static CloseableHttpClient getClient(RequestParam requestParam){
        String url = requestParam.getUrl();
        if(url.startsWith(HTTP_RPOTOCOL)){
            return HttpClients.createDefault();
        }else if(url.startsWith(HTTPS_RPOTOCOL)){
            return createSSLClientDefault();
        }else{
            throw new RuntimeException("不支持的协议类型");
        }
    }
}
